using System;
using System.Drawing;
using System.Runtime.InteropServices;

namespace Library.Winform.Screens {
	public class CaptureScreen {
		//This structure shall be used to keep the size of the screen.

		public static Bitmap CaptureDesktop() {
			SIZE size;
			IntPtr hDc = Win32Stuff.GetDC(Win32Stuff.GetDesktopWindow());
			IntPtr hMemDc = GdiStuff.CreateCompatibleDC(hDc);

			size.Cx = Win32Stuff.GetSystemMetrics
				(Win32Stuff.SmCxscreen);

			size.Cy = Win32Stuff.GetSystemMetrics
				(Win32Stuff.SmCyscreen);

			IntPtr hBitmap = GdiStuff.CreateCompatibleBitmap(hDc, size.Cx, size.Cy);

			if (hBitmap != IntPtr.Zero) {
				IntPtr hOld = GdiStuff.SelectObject
					(hMemDc, hBitmap);

				GdiStuff.BitBlt(hMemDc, 0, 0, size.Cx, size.Cy, hDc,
												0, 0, GdiStuff.Srccopy);

				GdiStuff.SelectObject(hMemDc, hOld);
				GdiStuff.DeleteDC(hMemDc);
				Win32Stuff.ReleaseDC(Win32Stuff.GetDesktopWindow(), hDc);
				Bitmap bmp = Image.FromHbitmap(hBitmap);
				GdiStuff.DeleteObject(hBitmap);
				GC.Collect();
				return bmp;
			}
			return null;
		}


		private static Bitmap CaptureCursor(ref int x, ref int y) {
			var ci = new Win32Stuff.Cursorinfo();
			Win32Stuff.Iconinfo icInfo;
			ci.cbSize = Marshal.SizeOf(ci);
			if (Win32Stuff.GetCursorInfo(out ci)) {
				if (ci.flags == Win32Stuff.CursorShowing) {
					IntPtr hicon = Win32Stuff.CopyIcon(ci.hCursor);
					if (Win32Stuff.GetIconInfo(hicon, out icInfo)) {
						x = ci.ptScreenPos.x - (icInfo.xHotspot);
						y = ci.ptScreenPos.y - (icInfo.yHotspot);

						Icon ic = Icon.FromHandle(hicon);
						Bitmap bmp = ic.ToBitmap();
						return bmp;
					}
				}
			}

			return null;
		}

		public static Bitmap CaptureDesktopWithCursor() {
			int cursorX = 0;
			int cursorY = 0;
			Graphics g;

			Bitmap desktopBmp = CaptureDesktop();
			Bitmap cursorBmp = CaptureCursor(ref cursorX, ref cursorY);
			if (desktopBmp != null) {
				if (cursorBmp != null) {
					var r = new Rectangle(cursorX, cursorY, cursorBmp.Width, cursorBmp.Height);
					g = Graphics.FromImage(desktopBmp);
					g.DrawImage(cursorBmp, r);
					g.Flush();

					return desktopBmp;
				}
				return desktopBmp;
			}

			return null;
		}

		#region Nested type: SIZE

		private struct SIZE {
			public int Cx;
			public int Cy;
		}

		#endregion
	}
}